<!DOCTYPE html>
<html>
<head>
<title>Attached callback of a custom element should be called if element is moved</title>
<meta name="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
<meta name="assert" content="attached callback ... must be enqueued whenever custom element is inserted into a document and this document has a browsing context.">
<link rel="help" href="http://www.w3.org/TR/custom-elements/#types-of-callbacks">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../../testcommon.js"></script>
<link rel="stylesheet" href="/resources/testharness.css">
</head>
<body>
<div id="log"></div>
<script>
test(function() {
    var doc = newHTMLDocument();
    var proto = newHTMLElementPrototype();
    doc.registerElement('x-a', {prototype: proto});
    var customElement = doc.createElement('x-a');

    doc.body.appendChild(customElement);
    assert_equals(proto.attachedCallbackCalledCounter, 0, 'Callback attached ' +
        'should not be called in documents that do not have a browsing context');

    var divElement = doc.createElement('div');
    doc.body.appendChild(divElement);
    divElement.appendChild(customElement);
    assert_equals(proto.attachedCallbackCalledCounter, 0, 'Callback attached ' +
        'should not be called in documents that do not have a browsing context');
}, 'Test attached callback if moving custom element inside document ' +
    'without browsing context');


testInIFrame('../../resources/blank.html', function(docWithBrowsingContext) {
    var docNoBrowsingContext = newHTMLDocument();
    var proto1 = newHTMLElementPrototype();
    docNoBrowsingContext.registerElement('x-b', {prototype: proto1});

    var customElement = docNoBrowsingContext.createElement('x-b');
    docNoBrowsingContext.body.appendChild(customElement);
    assert_equals(proto1.attachedCallbackCalledCounter, 0,
        'Callback attached should not be called ' +
        'in documents that do not have a browsing context');

    var proto2 = newHTMLElementPrototype();
    docWithBrowsingContext.registerElement('x-b', {prototype: proto2});
    docWithBrowsingContext.body.appendChild(customElement);
    assert_equals(proto1.attachedCallbackCalledCounter, 1,
        'Callback attached should be called in documents with browsing context');
    assert_equals(proto2.attachedCallbackCalledCounter, 0,
        'Callback attached, defined in receiving document, should not be called');
}, 'Test attached callback if moving custom element from ' +
    'document without browsing context to document with browsing context');


testInIFrame('../../resources/blank.html', function(docWithBrowsingContext) {
    var proto1 = newHTMLElementPrototype();
    docWithBrowsingContext.registerElement('x-c', {prototype: proto1});

    var customElement = docWithBrowsingContext.createElement('x-c');
    docWithBrowsingContext.body.appendChild(customElement);
    assert_equals(proto1.attachedCallbackCalledCounter, 1,
        'Callback attached should be called in documents with browsing context');

    var docNoBrowsingContext = newHTMLDocument();
    var proto2 = newHTMLElementPrototype();
    docNoBrowsingContext.registerElement('x-c', {prototype: proto2});
    docNoBrowsingContext.body.appendChild(customElement);
    assert_equals(proto1.attachedCallbackCalledCounter, 1, 'Callback attached should not be called ' +
        'in documents that do not have a browsing context');
    assert_equals(proto2.attachedCallbackCalledCounter, 0,
        'Callback attached, defined in receiving document, should not be called');
}, 'Test attached callback if moving custom element from ' +
    'document with browsing context to document without browsing context');


testInIFrame('../../resources/blank.html', function(doc) {
    var proto = newHTMLElementPrototype();
    doc.registerElement('x-d', {prototype: proto});

    var customElement = doc.createElement('x-d');
    doc.body.appendChild(customElement);
    assert_equals(proto.attachedCallbackCalledCounter, 1,
        'Callback attached should be called in documents with browsing context');

    var divElement = doc.createElement('div');
    doc.body.appendChild(divElement);
    divElement.appendChild(customElement);
    assert_equals(proto.attachedCallbackCalledCounter, 2,
        'Callback attached should be called in documents with browsing context');
}, 'Test attached callback if moving custom element inside document ' +
    'with browsing context');


testInIFrame('../../resources/blank.html', function(doc) {
    var proto = newHTMLElementPrototype();
    doc.registerElement('x-e', {prototype: proto});

    var customElement = doc.createElement('x-e');
    doc.body.appendChild(customElement);
    assert_equals(proto.attachedCallbackCalledCounter, 1,
        'Callback attached should be called in documents with browsing context');

    var divElement = doc.createElement('div');
    divElement.appendChild(customElement);
    assert_equals(proto.attachedCallbackCalledCounter, 1,
        'Callback attached should not be called if element is not appended to the document');

    doc.body.appendChild(divElement);
    assert_equals(proto.attachedCallbackCalledCounter, 2,
        'Callback attached should be called in documents with browsing context');
}, 'Test attached callback if indirectly moving custom element inside document ' +
    'with browsing context');


var moveTest =  async_test('Test attached callback if moving custom element from ' +
    'document with browsing context to document with browsing context');

moveTest.step(function() {
    var iframe1 = newIFrame('../../resources/blank.html');
    iframe1.onload = moveTest.step_func(function() {
        var doc1 = iframe1.contentDocument;

        // register custom element type
        var proto1 = newHTMLElementPrototype();
        doc1.registerElement('x-f', {prototype: proto1});

        // create custom element
        var customElement = doc1.createElement('x-f');
        doc1.body.appendChild(customElement);
        assert_equals(proto1.attachedCallbackCalledCounter, 1,
            'Callback attached should be called in documents with browsing context');

        // create second iframe
        var iframe2 = newIFrame('../../resources/x-element.html');
        iframe2.onload = moveTest.step_func(function() {
            var doc2 = iframe2.contentDocument;
            
            // register custom element type
            var proto2 = newHTMLElementPrototype();
            doc2.registerElement('x-f', {prototype: proto2});

            // move element
            doc2.body.appendChild(customElement);
            assert_equals(proto1.attachedCallbackCalledCounter, 2,
                'Callback attached should be called in documents with browsing context');
            assert_equals(proto2.attachedCallbackCalledCounter, 0,
                'Callback attached, defined in receiving document, should not be called');

            // test clean up
            iframe1.remove();
            iframe2.remove();
            moveTest.done();
        });
    });
});
</script>
</body>
</html>
